package com.gitee.liuzhi.demo.lambda;

/**
 * @Author liuzhi
 * @Date 2024/3/3 17:14
 * @Version 1.0
 * @Description FunctionInterface 函数式接口
 * <p>
 * 1. 函数式接口是使用 lambda 表达式的前提，只有确定接口中有且仅有一个抽象方法，lambda 才能顺利推导
 * 2. 接口可以拥有默认方法（即在类没有对方法进行实现时，其主体为方法提供默认实现的方法），哪怕有很多默认方法，只要接口定义了一个默认方法，它就是一个函数式接口）
 * 3. Lambda表达式可以作为函数式接口的一个具体实现的实例
 * <p>
 * FunctionInterface 语法
 * 1. 有且仅有一个抽象方法的接口
 * 2. 使用 @FunctionalInterface 注解进行标注（不是必须的，仅用于接口设计，类似于@Override）
 * <p>
 * FunctionInterface 作用
 * 1. 函数式接口一般可以作为方法的参数或者返回值
 * <p>
 * FunctionInterface 函数描述符
 * 1. 函数式接口的抽象方法的签名基本就是Lambda表达式的签名，也叫做函数描述符
 * 2. () -> void 代表了参数为空，且返回void的函数；(Apple a1, Apple a2) -> int 代表了接受两个Apple，返回一个int的函数
 * 3. Lambda在做类型检查时编译器会检查Lambda在给定的上下文是否有效，当然Lambda表达式的签名要和函数式接口的抽象方法（函数描述符）一致
 * 4. 如一个接收Runnable的方法，其函数描述符为不接受参数也不返回值，则可以process(() -> sout("111"))，因为Lambda与函数式接口的描述符一致
 * <p>
 * FunctionInterface 常见的函数式接口
 * 【Comparator、Runnable、Callable、PrivilegedAction】
 * 为了应用不同的Lambda表达式，Java API中已经定义了几个函数式接口 => java.util.function，Predicate，Consumer，Function
 * 1. 布尔表达式 -> Predicate
 * 2. 创建对象 -> Supplier
 * 3. 消费对象 -> Consumer
 * 4. 转换对象 -> Function<String, Integer>或ToIntFunction<String>
 * 5. 合并 -> IntBinaryOperator
 * 6. 比较 -> Comparator
 */
public class FunctionInterfaceDemo {

    public static void main(String[] args) {
        testCalculateMethod();
        testFunctionInterfaceAbstractDifferent();
    }

    private static void testCalculateMethod() {
        Integer num1 = 20;
        Integer num2 = 30;
        // 加法
        System.out.println(calculateMethod(num1, num2, Integer::sum));
        // 减法
        System.out.println(calculateMethod(num1, num2, (n1, n2) -> n1 - n2));
        // 乘法
        System.out.println(calculateMethod(num1, num2, (n1, n2) -> n1 * n2));
        // 除法
        System.out.println(calculateMethod(num1, num2, (n1, n2) -> n1 / n2));
    }

    /**
     * 使用函数式接口与使用匿名内部类的区别
     */
    private static void testFunctionInterfaceAbstractDifferent() {
        // 使用抽象类会显得比较笨拙
        // 使用抽象类
        calculateMethod(1, 2, new NumberCalculate() {
            @Override
            public Integer calculate(Integer num1, Integer num2) {
                return num1 + num2;
            }
        });
        // 使用函数式接口
        calculateMethod(1, 2, Integer::sum);
    }


    /**
     * 一个函数式接口作为参数的方法
     */
    private static Integer calculateMethod(Integer num1, Integer num2, NumberCalculate nc) {
        return nc.calculate(num1, num2);
    }

    /**
     * 一个函数式接口
     */
    @FunctionalInterface
    public interface NumberCalculate {
        Integer calculate(Integer num1, Integer num2);
    }

}
